package com.hibegin.http.server.impl;

import com.hibegin.http.server.SimpleWebServer;
import com.hibegin.http.server.config.RequestConfig;
import com.hibegin.http.server.config.ServerConfig;
import com.hibegin.http.server.util.HttpMethod;
import com.hibegin.http.server.web.cookie.Cookie;
import com.hibegin.http.server.web.session.HttpSession;
import com.hibegin.http.server.web.session.SessionUtil;
import com.szwistar.common.comm.HttpMultipartBodyParser.PartInfo;

import java.net.SocketAddress;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

public class HttpRequest {
    private SimpleWebServer server;
    private RequestConfig config;
    protected SocketAddress remoteHost;

    protected long createTime;

    protected HttpMethod method;
    protected String httpVersion;
    protected String uri;
    protected String queryStr;
    protected String bodyText;
    protected byte[] bodyBytes;

    private Cookie[] cookies;
    private HttpSession session;

    protected Map<String, String> header = new HashMap<String, String>();
    protected Map<String, String> paramMap = new HashMap<String, String>();
    protected Map<String, Object> attr;
    protected Map<String, PartInfo> fileParts;

    public SimpleWebServer getServer() { return server; }
    public ServerConfig getServerConfig() { return server.getServerConfig(); }
    public long getCreateTime() { return createTime; }
    public HttpMethod getMethod() { return method; }

    public String getBodyText() { return bodyText; }
	public byte[] getBodyBytes() { return bodyBytes; }
    public Map<String, PartInfo> getFileParts() { return fileParts; }

    @Override
	public String toString() {
    	return "HttpRequest: " + method.name() + " " + uri;
    }

	protected HttpRequest(SimpleWebServer server) {
        this.server = server;
        this.config = server.getRequestConfig();
        this.createTime = System.currentTimeMillis();
    }

    public String getHeader(String key) {
        String headerValue = header.get(key);
        if (headerValue != null) {
            return headerValue;
        }
        for (String hkey : header.keySet()) {
            if (hkey.equalsIgnoreCase(key)) {
                return header.get(hkey);
            }
        }
        return null;
    }

    /**
     * 获取对端主机IP地址
     */
    public SocketAddress getRemoteHost() { return remoteHost; }

    /**
     * 获取 HTTP 版本号
     * @return 如：HTTP/1.1
     */
    public String getHttpVersion() { return httpVersion; }

    /**
     * 获取请求的资源路径
     * @return 如：URL 为 "http://localhost:9404/path/func?name=zy&age=33" 时，返回 "/path/func"
     */
    public String getUri() { return uri; }

    /**
     * 获取不包括参数的 URL
     * @return 如：URL 为 "http://localhost:9404/path/func?name=zy&age=33" 时，返回 "http://localhost:9404/path/func"
     */
    public String getUrl() { return getScheme() + "://" + getHeader("Host") + uri; }

    /**
     * 获取完整 URL
     * @return 如：URL 为 "http://localhost:9404/path/func?name=zy&age=33" 时，原样返回 "http://localhost:9404/path/func?name=zy&age=33"
     */
    public String getFullUrl() { return (queryStr == null) ? getUrl() : getUrl() + "?" + queryStr; }

    /**
     * 获取查询字符串<br>
     * @return 如：URL 为 "http://localhost:9404/path/func?name=zy&age=33" 时，返回 "name=zy&age=33"
     */
    public String getQueryStr() { return queryStr; }

    /**
     * 获取协议名称
     * @return "http"/"https"
     */
    public String getScheme() { return config.isSsl() ? "https" : "http"; }

    /**
     * 获取请求配置参数
     */
    public RequestConfig getConfig() { return config; }

    /**
     * 获取静态 Web 资源根目录
     * @see 参见 {@link ServerConfig#getWebRootPath()}
     */
    public String getRealPath() {
        return server.getServerConfig().getWebRootPath();
    }

	/**
	 * 是否需要保持连接
	 */
    public boolean keepAlive() {
		return server.getServerConfig().isKeepAlive() && "keep-alive".equalsIgnoreCase(header.get("Connection"));
	}

    /**
     * 获取自定义属性 MAP
     */
    public Map<String, Object> getAttr() {
        if (attr == null) {
            attr = Collections.synchronizedMap(new HashMap<String, Object>());
        }
        return attr;
    }

    public Cookie[] getCookies() {
        if (cookies == null) {
            dealWithCookie(false);
        }
        if (cookies == null) {
            cookies = new Cookie[0];
        }
        return cookies;
    }

    private void dealWithCookie(boolean create) {
        if (!config.isDisableCookie()) {
            String cookieHeader = getHeader("Cookie");
            if (cookieHeader != null) {
                cookies = Cookie.saxToCookie(cookieHeader);
                String jsessionid = Cookie.getJSessionId(cookieHeader, getServerConfig().getSessionId());
                if (jsessionid != null) {
                    session = SessionUtil.getSessionById(jsessionid);
                }
            }
            if (create && session == null) {
                if (cookies == null) {
                    cookies = new Cookie[1];
                } else {
                    cookies = new Cookie[cookies.length + 1];
                }
                Cookie cookie = new Cookie(true);
                String jsessionid = UUID.randomUUID().toString();
                cookie.setName(getServerConfig().getSessionId());
                cookie.setPath("/");
                cookie.setValue(jsessionid);
                cookies[cookies.length - 1] = cookie;
                session = new HttpSession(jsessionid);
                SessionUtil.sessionMap.put(jsessionid, session);
                //LOG.info("create a cookie " + cookie.toString());
            }
        }
    }

    public HttpSession getSession() {
        if (session == null) {
            dealWithCookie(true);
        }
        return session;
    }

    public String getParaToStr(String key, String defaultValue) {
        if (paramMap.get(key) != null) {
            return paramMap.get(key).toString();
        }
        return defaultValue;
    }

    public int getParaToInt(String key, int defaultValue) {
        if (paramMap.get(key) != null) {
        	try {
        		return Integer.parseInt(paramMap.get(key));
        	} catch(Exception e) {
        	}
        }
        return defaultValue;
    }

    public float getParaToFloat(String key, float defaultValue) {
        if (paramMap.get(key) != null) {
        	try {
                return Float.parseFloat(paramMap.get(key));
        	} catch(Exception e) {
        	}
        }
        return defaultValue;
    }

    public boolean getParaToBool(String key, boolean defaultValue) {
    	String val = paramMap.get(key);
        if (val != null) {
            return "true".equalsIgnoreCase(val) ||
            	   "yes".equalsIgnoreCase(val) ||
            	   "enable".equalsIgnoreCase(val) ||
            	   "enabled".equalsIgnoreCase(val) ||
            	   "on".equalsIgnoreCase(val) ||
            	   "1".equalsIgnoreCase(val);
        }
        return defaultValue;
    }
}
